
%{
/*#define YYDEBUG 1*/
	#include <stdio.h>
	#include <stdlib.h>
	#include <stdarg.h>
	#include "../AST/ASTHeader.h"
	#include "../symtab/symtab.h"
	
	/* prototypes */
	
	int ex(ASTNode *p);
	int yylex(void);
	
	void yyerror(char *s);

	extern symtab * pCurSymTab;
	TranslationUnit *pFinalTransUnit = NULL;
%}



%union {
	int iValue;
	void * pAST;
	char *strName;
};


%token CONSTANT STRING_LITERAL SIZEOF TYPENAME

%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP

%token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN

%token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN

%token XOR_ASSIGN OR_ASSIGN TYPE_NAME



%token TYPEDEF EXTERN STATIC AUTO REGISTER RESTRICT INLINE

%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID _BOOL _COMPLEX _IMAGINARY

%token STRUCT UNION ENUM ELLIPSIS



%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN

%token<pAST> IDENTIFIER 

%nonassoc IFX
%nonassoc ELSE

%start translation_unit

%type <pAST> primary_expression postfix_expression argument_expression_list unary_expression unary_operator cast_expression multiplicative_expression additive_expression shift_expression relational_expression equality_expression and_expression exclusive_or_expression inclusive_or_expression logical_and_expression logical_or_expression conditional_expression assignment_expression assignment_operator expression constant_expression declaration declaration_specifiers init_declarator_list init_declarator storage_class_specifier type_specifier struct_or_union_specifier struct_or_union struct_declaration_list struct_declaration specifier_qualifier_list struct_declarator_list  struct_declarator enum_specifier enumerator_list enumerator type_qualifier function_specifier declarator direct_declarator pointer type_qualifier_list parameter_type_list parameter_list parameter_declaration identifier_list type_name abstract_declarator direct_abstract_declarator typedef_name initializer initializer_list designation designator_list designator statement labeled_statement compound_statement block_item_list block_item expression_statement selection_statement iteration_statement jump_statement translation_unit external_declaration function_definition declaration_list 
%%



primary_expression:
	 IDENTIFIER											{ $$ = new PrimaryExpr((sym *)yylval.pAST,PrimaryExpr::identifier); }
     | CONSTANT
     | STRING_LITERAL
	 | '(' expression ')'								{ $$ = new PrimaryExpr((Expression *)$2); }
	   ;



postfix_expression  :
	primary_expression									{ $$ = new PostfixExpr((PrimaryExpr *)$1); }
	| postfix_expression '[' expression ']'				{ $$ = new PostfixExpr((PostfixExpr *)$1, (Expression *)$3) ;}
	| postfix_expression '(' ')'						{ $$ = new PostfixExpr((PostfixExpr *)$1, PostfixExpr::function_call_no_argument); }
    | postfix_expression '(' argument_expression_list ')'		{ $$ = new PostfixExpr((PostfixExpr *)$1, (ArgumentExprList *)$3);}
    | postfix_expression '.' IDENTIFIER					{ $$ = new PostfixExpr((PostfixExpr *)$1, (sym *)$3, PostfixExpr::point_expression); }
    | postfix_expression PTR_OP IDENTIFIER				{ $$ = new PostfixExpr((PostfixExpr *)$1, (sym *)$3, PostfixExpr::arrow_expression); }
    | postfix_expression INC_OP							{ $$ = new PostfixExpr((PostfixExpr *)$1, PostfixExpr::plus_expression); }
    | postfix_expression DEC_OP							{ $$ = new PostfixExpr((PostfixExpr *)$1, PostfixExpr::sub_expression); }
	| '(' type_name ')' '{' initializer_list '}'		{ $$ = new PostfixExpr((TypeName *)$2, (InitializerList *)$5); }
	| '(' type_name ')' '{' initializer_list ',' '}'	{ $$ = new PostfixExpr((TypeName *)$2, (InitializerList *)$5); }
	 ;



argument_expression_list :
	assignment_expression								{ $$ = new ArgumentExprList((AssignmentExpr *)$1); }
	| argument_expression_list ',' assignment_expression	{ $$ = new ArgumentExprList((ArgumentExprList *)$1, (AssignmentExpr *)$3); }
	;

unary_expression :
	postfix_expression									{ $$ = new UnaryExpr((PostfixExpr *)$1); }
	| INC_OP unary_expression							{ $$ = new UnaryExpr((UnaryExpr *)$2, UnaryExpr::plus_unary_expr); }
	| DEC_OP unary_expression							{ $$ = new UnaryExpr((UnaryExpr *)$2, UnaryExpr::sub_unary_expr); }
	| unary_operator cast_expression					{ $$ = new UnaryExpr((CastExpr *)$2, (UnaryOperator *)$1); }
	| SIZEOF unary_expression							{ $$ = new UnaryExpr((UnaryExpr *)$2, UnaryExpr::sizeof_expr); }
    | SIZEOF '(' type_name ')'							{ $$ = new UnaryExpr((sym *)$3); }
	 ;

unary_operator :
	'&'													{ $$ = new UnaryOperator('&'); }
	| '*'												{ $$ = new UnaryOperator('*'); }
	| '+'												{ $$ = new UnaryOperator('+'); }
	| '-'												{ $$ = new UnaryOperator('-'); }																								
	| '~'												{ $$ = new UnaryOperator('~'); }
	| '!'												{ $$ = new UnaryOperator('!'); }
	 ;

cast_expression :
	unary_expression							{$$ = new CastExpr((UnaryExpr *)$1);}
	| '(' type_name ')' cast_expression			{ $$ = new CastExpr((sym *)$2, (CastExpr *)$4); }
	 ;

multiplicative_expression : 
	cast_expression										{ $$ = new MultiplicativeExpr((CastExpr *)$1); }
	| multiplicative_expression '*' cast_expression		{ $$ = new MultiplicativeExpr((MultiplicativeExpr *)$1, '*', (CastExpr *)$3); }
	| multiplicative_expression '/' cast_expression		{ $$ = new MultiplicativeExpr((MultiplicativeExpr *)$1, '/', (CastExpr *)$3); }
	| multiplicative_expression '%' cast_expression		{ $$ = new MultiplicativeExpr((MultiplicativeExpr *)$1, '%', (CastExpr *)$3); }
	 ;


additive_expression : 
	multiplicative_expression							{ $$ = new AdditiveExpr((MultiplicativeExpr *)$1); }
	| additive_expression '+' multiplicative_expression	{ $$ = new AdditiveExpr((MultiplicativeExpr *)$3,'+', (AdditiveExpr *)$1); }
	| additive_expression '-' multiplicative_expression	{ $$ = new AdditiveExpr((MultiplicativeExpr *)$3,'-', (AdditiveExpr *)$1); }
	;

shift_expression :
	additive_expression									{ $$ = new ShiftExpr((AdditiveExpr *)$1); }
	| shift_expression LEFT_OP additive_expression		{ $$ = new ShiftExpr((ShiftExpr *)$1, ShiftExpr::left_shift_expr, (AdditiveExpr *)$3); }
	| shift_expression RIGHT_OP additive_expression		{ $$ = new ShiftExpr((ShiftExpr *)$1, ShiftExpr::right_shift_expr, (AdditiveExpr *)$3); }
	;



relational_expression : 
	shift_expression									{ $$ = new RelationalExpr((ShiftExpr *)$1); }
	| relational_expression '<' shift_expression		{ $$ = new RelationalExpr((RelationalExpr *)$1, RelationalExpr::small_expr, (ShiftExpr *)$3); }
	| relational_expression '>' shift_expression		{ $$ = new RelationalExpr((RelationalExpr *)$1, RelationalExpr::large_expr, (ShiftExpr *)$3); }
	| relational_expression LE_OP shift_expression		{ $$ = new RelationalExpr((RelationalExpr *)$1, RelationalExpr::small_equal_expr, (ShiftExpr *)$3); }
	| relational_expression GE_OP shift_expression		{ $$ = new RelationalExpr((RelationalExpr *)$1, RelationalExpr::large_equal_expr, (ShiftExpr *)$3); }
	;



equality_expression :
	relational_expression								{ $$ = new EqualityExpr((RelationalExpr *)$1); }
	| equality_expression EQ_OP relational_expression	{ $$ = new EqualityExpr((EqualityExpr *)$1, EqualityExpr::equal_expr, (RelationalExpr *)$3); }
	| equality_expression NE_OP relational_expression	{ $$ = new EqualityExpr((EqualityExpr *)$1, EqualityExpr::no_equal_expr, (RelationalExpr *)$3); }
	;



and_expression : 
	equality_expression									{ $$ = new AndExpr((EqualityExpr *)$1); }
	| and_expression '&' equality_expression			{ $$ = new AndExpr((AndExpr *)$1, (EqualityExpr *)$3); }
	;


exclusive_or_expression : 
	and_expression										{ $$ = new ExclusiveORExpr((AndExpr *)$1); }
	| exclusive_or_expression '^' and_expression		{ $$ = new ExclusiveORExpr((ExclusiveORExpr *)$1, (AndExpr *)$3); }
	;

inclusive_or_expression : 
	exclusive_or_expression								{ $$ = new InclusiveORExpr((ExclusiveORExpr *)$1); }
	| inclusive_or_expression '|' exclusive_or_expression	{ $$ = new InclusiveORExpr((InclusiveORExpr *)$1, (ExclusiveORExpr *)$3); }
	;



logical_and_expression :		
	inclusive_or_expression								{ $$ = new LogicalANDExpr((InclusiveORExpr *)$1); }		
	| logical_and_expression AND_OP inclusive_or_expression	{ $$ = new LogicalANDExpr((LogicalANDExpr *)$1, (InclusiveORExpr *)$3); }
	;

logical_or_expression :
	logical_and_expression								{ $$ = new LogicalORExpr((LogicalANDExpr *)$1); }
	| logical_or_expression OR_OP logical_and_expression	{ $$ = new LogicalORExpr((LogicalORExpr *)$1, (LogicalANDExpr *)$3); }
	;



conditional_expression :
	logical_or_expression								{ $$ = new ConditionalExpr((LogicalORExpr *)$1); }
	| logical_or_expression '?' expression ':' conditional_expression	{ $$ = new ConditionalExpr((LogicalORExpr *) $1, (Expression *)$3, (ConditionalExpr *)$5); }
	;



assignment_expression :
	conditional_expression								{ $$ = new AssignmentExpr((ConditionalExpr *)$1); }
	| unary_expression assignment_operator assignment_expression	{ $$ = new AssignmentExpr((UnaryExpr *)$1, (AssignmentOperator *)$2, (AssignmentExpr *)$3); }
	;


assignment_operator : 
	'='													{ $$ = new AssignmentOperator(AssignmentOperator::equality); }
	| MUL_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::mul_equality); }
	| DIV_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::div_equality); }
    | MOD_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::mod_equality); }
    | ADD_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::add_equality); }
    | SUB_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::sub_equality); }
    | LEFT_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::lsh_equality); }
    | RIGHT_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::rsh_equality); }
    | AND_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::and_equality); }
    | XOR_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::xor_equality); }
    | OR_ASSIGN										{ $$ = new AssignmentOperator(AssignmentOperator::or_equality); }
	 ;

expression : 
	assignment_expression								{ $$ = new Expression((AssignmentExpr *)$1); }
	| expression ',' assignment_expression				{ $$ = new Expression((Expression *)$1, (AssignmentExpr *)$3); }
	;



constant_expression :
	conditional_expression								{ $$ = new ConstantExpr((ConditionalExpr *)$1); }
	;



declaration :
	declaration_specifiers ';'							{ $$ = new Declaration((DeclarationSpecifiers *)$1); }
	| declaration_specifiers init_declarator_list ';'	{ $$ = new Declaration((DeclarationSpecifiers *)$1, (InitDeclaratorList *)$2); }
	;

declaration_specifiers :
	storage_class_specifier								{ $$ = new DeclarationSpecifiers((StorageClassSpecifier *)$1); }
	| storage_class_specifier declaration_specifiers	{ $$ = new DeclarationSpecifiers((StorageClassSpecifier *)$1,(DeclarationSpecifiers *)$2); }
	| type_specifier									{ $$ = new DeclarationSpecifiers((TypeSpecifier *)$1); }
	| type_specifier declaration_specifiers				{ $$ = new DeclarationSpecifiers((TypeSpecifier *)$1, (DeclarationSpecifiers *)$2); }
	| type_qualifier									{ $$ = new DeclarationSpecifiers((TypeQualifier *)$1); }
	| type_qualifier declaration_specifiers				{ $$ = new DeclarationSpecifiers((TypeQualifier *)$1, (DeclarationSpecifiers *)$2); }
	| function_specifier								{ $$ = new DeclarationSpecifiers((FunctionSpecifier *)$1);}
	| function_specifier declaration_specifiers			{ $$ = new DeclarationSpecifiers((FunctionSpecifier *)$1, (DeclarationSpecifiers *)$2);}
	;


init_declarator_list : 
	init_declarator										{ $$ = new InitDeclaratorList((InitDeclarator *)$1); }
	| init_declarator_list ',' init_declarator			{ $$ = new InitDeclaratorList((InitDeclarator *)$1,(InitDeclaratorList *)$3); }
	;

init_declarator : 
	declarator											{ $$ = new InitDeclarator((Declarator *)$1); }
	| declarator '=' initializer						{ $$ = new InitDeclarator((Declarator *)$1, (Initializer *)$3); }
	;

storage_class_specifier :
	TYPEDEF												{ $$ = new StorageClassSpecifier(StorageClassSpecifier::_typedef); }
	| EXTERN											{ $$ = new StorageClassSpecifier(StorageClassSpecifier::_extern); }
	| STATIC											{ $$ = new StorageClassSpecifier(StorageClassSpecifier::_static); }
	| AUTO												{ $$ = new StorageClassSpecifier(StorageClassSpecifier::_auto); }
	| REGISTER											{ $$ = new StorageClassSpecifier(StorageClassSpecifier::_register); }
	;


type_specifier :
	VOID												{ $$ = new TypeSpecifier(TypeSpecifier::_void); }
	| CHAR												{ $$ = new TypeSpecifier(TypeSpecifier::_char); }
	| SHORT												{ $$ = new TypeSpecifier(TypeSpecifier::_short); }
	| INT												{ $$ = new TypeSpecifier(TypeSpecifier::_int); }
	| LONG												{ $$ = new TypeSpecifier(TypeSpecifier::_long); }
	| FLOAT												{ $$ = new TypeSpecifier(TypeSpecifier::_float); }
	| DOUBLE											{ $$ = new TypeSpecifier(TypeSpecifier::_double); }
	| SIGNED											{ $$ = new TypeSpecifier(TypeSpecifier::_signed); }
	| UNSIGNED											{ $$ = new TypeSpecifier(TypeSpecifier::_unsigned); }
	| _BOOL												{ $$ = new TypeSpecifier(TypeSpecifier::__Bool); }
	| _COMPLEX											{ $$ = new TypeSpecifier(TypeSpecifier::__Complex); }
	| _IMAGINARY										{ $$ = new TypeSpecifier(TypeSpecifier::__Imaginary); }
	| struct_or_union_specifier							{ $$ = new TypeSpecifier((StructOrUnionSpecifier *) $1); }
	| enum_specifier									{ $$ = new TypeSpecifier((EnumSpecifier *) $1); }
	| typedef_name										{ $$ = new TypeSpecifier((TypeName *) $1); }
	;


struct_or_union_specifier : 
	struct_or_union IDENTIFIER '{' struct_declaration_list '}'			{((sym *)$2)->m_iSymCategory = sym::struct_union_name;$$ = new StructOrUnionSpecifier((StructOrUnion *)$1,(sym *)$2, (StructDeclarationList *)$4); }
	| struct_or_union '{' struct_declaration_list '}'					{ $$ = new StructOrUnionSpecifier((StructOrUnion *)$1,(sym *)NULL, (StructDeclarationList *)$3); }
	| struct_or_union IDENTIFIER										{((sym *)$2)->m_iSymCategory = sym::struct_union_name;$$ = new StructOrUnionSpecifier((StructOrUnion *)$1,(sym *)$2, NULL); }
	;


struct_or_union :
	STRUCT																{ $$ = new StructOrUnion(StructOrUnion::_struct); }
	| UNION																{ $$ = new StructOrUnion(StructOrUnion::_union); }
	;


struct_declaration_list : 
	struct_declaration													{ $$ = new StructDeclarationList((StructDeclaration *)$1); }
	| struct_declaration_list struct_declaration						{ $$ = new StructDeclarationList((StructDeclaration *)$2, (StructDeclarationList *)$1); }
	;


struct_declaration :
	specifier_qualifier_list struct_declarator_list ';'					{ $$ = new StructDeclaration((SpecifierQualifierList *)$1, (StructDeclaratorList *)$2); }
	;



specifier_qualifier_list :
	type_specifier specifier_qualifier_list								{ $$ = new SpecifierQualifierList((TypeSpecifier *)$1, (SpecifierQualifierList *)$2); }
	| type_specifier													{ $$ = new SpecifierQualifierList((TypeSpecifier *)$1); }
	| type_qualifier specifier_qualifier_list							{ $$ = new SpecifierQualifierList((TypeQualifier *)$1, (SpecifierQualifierList *)$2); }
	| type_qualifier													{ $$ = new SpecifierQualifierList((TypeQualifier *)$1); }
	;


struct_declarator_list :
	struct_declarator													{ $$ = new StructDeclaratorList((StructDeclarator *)$1); }
	| struct_declarator_list ',' struct_declarator						{ $$ = new StructDeclaratorList((StructDeclarator *)$3,(StructDeclaratorList *)$1); }
	;


struct_declarator : 
	declarator															{ $$ = new StructDeclarator((Declarator *)$1); }
	| ':' constant_expression											{ $$ = new StructDeclarator((ConstantExpr *)$2); }
	| declarator ':' constant_expression								{ $$ = new StructDeclarator((ConstantExpr *)$3, (Declarator *)$1); }
	;


enum_specifier :
	ENUM '{' enumerator_list '}'										{ $$ = new EnumSpecifier((EnumeratorList *)$3); }
	| ENUM IDENTIFIER '{' enumerator_list '}'							{ ((sym *)$2)->m_iSymCategory = sym::type_name; $$ = new EnumSpecifier((EnumeratorList *)$4, (sym *)$2); }
	| ENUM '{' enumerator_list ',' '}'									{ $$ = new EnumSpecifier((EnumeratorList *)$3); }
	| ENUM IDENTIFIER '{' enumerator_list ',' '}'						{ sym *pSym = (sym *)$2; pSym->m_iSymCategory = sym::type_name; $$ = new EnumSpecifier((EnumeratorList *)$4, (sym *)$2); }
	| ENUM IDENTIFIER													{ sym *pSym = (sym *)$2; pSym->m_iSymCategory = sym::type_name; $$ = new EnumSpecifier((sym *)$2); }
	;

enumerator_list : 
	enumerator									{ $$ = new EnumeratorList((Enumerator *)$1); }
	| enumerator_list ',' enumerator			{ $$ = new EnumeratorList((Enumerator *)$3, (EnumeratorList *)$1); }
	;

enumerator :
	IDENTIFIER									{ sym *pSym = (sym *)$1; pSym->m_iSymCategory = sym::enum_name; $$ = new Enumerator((sym *)$1); }
	| IDENTIFIER '=' constant_expression		{ sym *pSym = (sym *)$1; pSym->m_iSymCategory = sym::enum_name; $$ = new Enumerator((sym *)$1, (ConstantExpr *)$3); }
	;



type_qualifier :
	CONST										{ $$ = new TypeQualifier(TypeQualifier::TQualConst); }
	| VOLATILE									{ $$ = new TypeQualifier(TypeQualifier::TQualVolatile); }
	| RESTRICT									{ $$ = new TypeQualifier(TypeQualifier::TQualRestrict); }
	;
	
function_specifier :
	INLINE										{ $$ = new FunctionSpecifier(); }
	;


declarator :
	pointer direct_declarator					{ $$ = new Declarator((DirectDeclarator *)$2, (Pointer *)$3);}
	| direct_declarator							{ $$ = new Declarator((DirectDeclarator *)$1); }
	;


direct_declarator :
	IDENTIFIER									{ $$ = new DirectDeclarator((sym *)$1); }
	| '(' declarator ')'						{ $$ = new DirectDeclarator((Declarator *)$2); }
	| direct_declarator '[' ']'					{ $$ = new DirectDeclarator((DirectDeclarator *)$1);}
	| direct_declarator '[' type_qualifier_list ']'	{ $$ = new DirectDeclarator((DirectDeclarator *)$1, (TypeQualifierList *)$3);}
	| direct_declarator '[' type_qualifier_list assignment_expression ']'	{ $$ = new DirectDeclarator((DirectDeclarator *)$1, (TypeQualifierList *)$3, (AssignmentExpr *) $4);}
	| direct_declarator '[' assignment_expression ']'	{ $$ = new DirectDeclarator( (DirectDeclarator *)$1, NULL, (AssignmentExpr *)$3);}
	| direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' {$$ = new DirectDeclarator( (DirectDeclarator *)$1, (TypeQualifierList *)$4, (AssignmentExpr *)$5 );} 
	| direct_declarator '[' STATIC assignment_expression ']'	{$$ = new DirectDeclarator((DirectDeclarator *)$1, NULL, (AssignmentExpr *)$4);}
	| direct_declarator '[' type_qualifier_list STATIC assignment_expression ']'	{ $$ = new DirectDeclarator((DirectDeclarator *)$1, (TypeQualifierList *)$3, (AssignmentExpr *)$5);}
	| direct_declarator '[' type_qualifier_list '*' ']'	{$$ = new DirectDeclarator((DirectDeclarator *)$1, (TypeQualifierList *) $3); }
	| direct_declarator '[' '*' ']'				{$$ = new DirectDeclarator((DirectDeclarator *)$1);}
	| direct_declarator '(' parameter_type_list ')'	{$$ = new DirectDeclarator((DirectDeclarator *)$1, (ParameterTypeList *)$3);}
	| direct_declarator '(' identifier_list ')'	{$$ = new DirectDeclarator((DirectDeclarator *)$1, (IdentifierList *) $3);}
	| direct_declarator '(' ')'					{$$ = new DirectDeclarator();}
	;


pointer :
	'*'									{ $$ = new Pointer();}
	| '*' type_qualifier_list			{ $$ = new Pointer((TypeQualifierList *)$2);}
	| '*' pointer						{ $$ = new Pointer((Pointer *) $2);}
	| '*' type_qualifier_list pointer	{ $$ = new Pointer((Pointer *) $3, (TypeQualifierList *)$2);}
	;

type_qualifier_list :
	type_qualifier						{ $$ = new TypeQualifierList((TypeQualifier *)$1);}
	| type_qualifier_list type_qualifier	{ $$ = new TypeQualifierList((TypeQualifier *)$1, (TypeQualifier *)$2);}
	;

parameter_type_list :
	parameter_list						{ $$ = new ParameterTypeList((ParameterList *) $1);}
	| parameter_list ',' ELLIPSIS		{ $$ = new ParameterTypeList((ParameterList *) $1, ParameterTypeList::non_determin_args);}
	;

parameter_list :
	parameter_declaration				{ $$ = new ParameterList((ParameterDeclaration *)$1);}
	| parameter_list ',' parameter_declaration	{ $$ = new ParameterList((ParameterDeclaration *)$1, (ParameterList *)$3);}
	;

parameter_declaration :
	declaration_specifiers declarator	{ $$ = new ParameterDeclaration((DeclarationSpecifiers *)$1, (Declarator *)$2);}
	| declaration_specifiers abstract_declarator	{ $$ = new ParameterDeclaration((DeclarationSpecifiers *)$1, (AbstractDeclarator *)$2);}
	| declaration_specifiers			{ $$ = new ParameterDeclaration((DeclarationSpecifiers *)$1);}
	;

identifier_list :
	IDENTIFIER							{ $$ = new IdentifierList((sym *)$1); }
	| identifier_list ',' IDENTIFIER	{ $$ = new IdentifierList((sym *)$3, (IdentifierList *)$1); }
	;


type_name :
	specifier_qualifier_list			{ $$ = new TypeName((SpecifierQualifierList *)$1);}
	| specifier_qualifier_list abstract_declarator { $$ = new TypeName((SpecifierQualifierList *)$1, (AbstractDeclarator *)$2);}
	;

abstract_declarator :
	pointer								{ $$ = new AbstractDeclarator((Pointer *)$1);}
	| direct_abstract_declarator		{ $$ = new AbstractDeclarator(NULL, (DirectAbstractDeclarator *)$2);}
	| pointer direct_abstract_declarator	{ $$ = new AbstractDeclarator((Pointer *)$1, (DirectAbstractDeclarator *)$2);}
	;

direct_abstract_declarator :
	'(' abstract_declarator ')'				{;}
	|  '['  ']'
	| '[' type_qualifier_list ']'
	| '[' assignment_expression ']'
	| '[' STATIC type_qualifier_list ']'
	| direct_abstract_declarator '[' ']'
	| direct_abstract_declarator '[' type_qualifier_list ']'
	| direct_abstract_declarator '[' assignment_expression ']'
	| direct_abstract_declarator '[' STATIC type_qualifier_list ']'
	|  '('  ')'
	| '(' parameter_type_list ')'
	| direct_abstract_declarator '(' ')'
	| direct_abstract_declarator '(' parameter_type_list ')'
	;

typedef_name:
	TYPENAME			{ ;}
	;

initializer :
	assignment_expression					{ $$ = new Initializer( (AssignmentExpr *)$1);}
	| '{' initializer_list '}'				{ $$ = new Initializer((InitializerList *)$2);}
	| '{' initializer_list ',' '}'			{ $$ = new Initializer((InitializerList *)$2);}
	;

initializer_list :
	initializer								{ $$ = new InitializerList((Initializer *)$1, NULL, NULL);}
	| initializer_list ',' initializer		{ $$ = new InitializerList((Initializer *)$3, NULL, (InitializerList *)$1);}
	| initializer_list ',' designation initializer	{ $$ = new InitializerList((Initializer *)$4, (Designation *)$3, (InitializerList *)$1);}
	;

designation:
	designator_list '='			{ $$ = new Designation((DesignatorList *)$1);}
	;
	
designator_list:
	designator					{ $$ = new DesignatorList((Designator *)$1);}
	| designator_list designator	{ $$ = new DesignatorList((Designator *)$2, (DesignatorList *)$1);}
	;
	
designator :
	'[' constant_expression ']'	{ $$ = new Designator((ConstantExpr *)$2);}
	| '.' IDENTIFIER			{ $$ = new Designator((sym *)$2);}
	;
	
statement :
	labeled_statement								{ $$ = new Statement((LabeledStmt *) $1); }
	| compound_statement							{ $$ = new Statement((CompoundStmt *) $1); }
	| expression_statement							{ $$ = new Statement((ExpressionStmt *) $1); }
	| selection_statement							{ $$ = new Statement((SelectionStmt *) $1); }
	| iteration_statement							{ $$ = new Statement((IterationStmt *) $1); }
	| jump_statement								{ $$ = new Statement((JumpStmt *) $1); }
	;

labeled_statement :
	IDENTIFIER ':' statement						{ sym *pSym = (sym *)$1; pSym->m_iSymCategory = sym::label_name;$$ = new LabeledStmt((sym *)$1, (Statement *)$3); }
	| CASE constant_expression ':' statement		{ $$ = new LabeledStmt((Statement *) $4, (ConstantExpr *)$2); }
	| DEFAULT ':' statement							{ $$ = new LabeledStmt((Statement *)$3); }
	;

compound_statement :
	 '{' '}'										{ $$ = new CompoundStmt(); }
	| '{' block_item_list '}'						{ $$ = new CompoundStmt((BlockItemList *)$2); }
	;

block_item_list :
	block_item										{ $$ = new BlockItemList((BlockItem *)$1); }
	| block_item_list block_item					{ $$ = new BlockItemList((BlockItem *)$2, (BlockItemList *)$1); }
	;
	
block_item :
	declaration										{ $$ = new BlockItem((Declaration *) $1); }
	| statement										{ $$ = new BlockItem((Statement *) $1); }
	;
	
expression_statement :
	';'												{ $$ = new ExpressionStmt(); }
	| expression ';'								{ $$ = new ExpressionStmt((Expression *)$1); }
	;
	

selection_statement :
	IF '(' expression ')' statement %prec IFX		{ $$ = new SelectionStmt((Expression *)$3, (Statement *)$5, NULL, SelectionStmt::if_stmt); }
	| IF '(' expression ')' statement ELSE statement	{ $$ = new SelectionStmt((Expression *)$3, (Statement *)$5, (Statement *)$7, SelectionStmt::else_stmt); }
	| SWITCH '(' expression ')' statement			{ $$ = new SelectionStmt((Expression *)$3, (Statement *)$5, NULL, SelectionStmt::switch_stmt); }
	;

iteration_statement :
	WHILE '(' expression ')' statement				{ $$ = new IterationStmt((Expression *)$3, (Statement *)$5, IterationStmt::while_stmt); }
	| DO statement WHILE '(' expression ')' ';'		{ $$ = new IterationStmt((Expression *)$5, (Statement *)$2, IterationStmt::do_stmt); }
	| FOR '(' ';' ';' ')' statement					{ $$ = new IterationStmt((Expression *)NULL,NULL,NULL,(Statement *)$6); }
	| FOR '(' ';' ';' expression ')' statement		{ $$ = new IterationStmt((Expression *)NULL,NULL,(Expression *)$5, (Statement *)$7); }
	| FOR '(' ';' expression ';' expression ')' statement	{ $$ = new IterationStmt((Expression *)NULL, (Expression *)$4, (Expression *)$6,(Statement *)$8); }
	| FOR '(' expression ';' expression ';' expression ')' statement	{ $$ = new IterationStmt((Expression *)$3, (Expression *)$5, (Expression *)$7, (Statement *)$9); }
	| FOR '(' expression ';' ';' ')' statement		{ $$ = new IterationStmt((Expression *)$3, NULL,NULL,(Statement *)$7); }
	| FOR '(' expression ';' expression ';' ')' statement	{ $$ = new IterationStmt((Expression *)$3, (Expression *)$5, NULL, (Statement *)$8); }
	| FOR '(' ';' expression ';' ')' statement		{ $$ = new IterationStmt((Expression *)NULL, (Expression *)$4, NULL, (Statement *)$7); }
	| FOR '(' expression ';' ';' expression ')' statement	{ $$ = new IterationStmt((Expression *)$3, NULL, (Expression *)$6, (Statement *)$8); }
	| FOR '(' declaration ';' ')' statement			{ $$ = new IterationStmt((Declaration *)$3, NULL,NULL,(Statement *)$6); }
	| FOR '(' declaration ';' expression ')' statement	{ $$ = new IterationStmt((Declaration *)$3, NULL,(Expression *)$5,(Statement *)$7); }
	| FOR '(' declaration expression ';' ')' statement	{ $$ = new IterationStmt((Declaration *)$3, (Expression *)$4,NULL, (Statement *)$7); }
	| FOR '(' declaration expression ';' expression ')' statement	{ $$ = new IterationStmt((Declaration *)$3, (Expression *)$4, (Expression *)$6, (Statement *)$8); }
	;

jump_statement :
	GOTO IDENTIFIER ';'									{ sym *p = (sym *)$2; p->m_iSymCategory = sym::label_name; $$ = new JumpStmt((sym *)$2); }
	| CONTINUE ';'										{ $$ = new JumpStmt(JumpStmt::continue_stmt); }
	| BREAK ';'											{ $$ = new JumpStmt(JumpStmt::break_stmt); }
	| RETURN ';'										{ $$ = new JumpStmt(); }
	| RETURN expression ';'								{ $$ = new JumpStmt((Expression *)$2); }
	;


translation_unit:
	external_declaration						{ $$ = new TranslationUnit((ExternalDeclaration *)$1); }
	| translation_unit external_declaration		{ if(pFinalTransUnit== NULL) {pFinalTransUnit= new TranslationUnit( (TranslationUnit *)$1, (ExternalDeclaration *)$2);pFinalTransUnit->codeGen();	exit(0); } else $$ = new TranslationUnit((TranslationUnit *)$1, (ExternalDeclaration *)$2); }
	;


external_declaration : 
	function_definition							{$$ = new ExternalDeclaration((FunctionDefinition *)$1);}
    | declaration								{$$ = new ExternalDeclaration((Declaration *)$1);}
	;


function_definition :
	declaration_specifiers declarator declaration_list compound_statement		{$$ = new FunctionDefinition((DeclarationSpecifiers *)$1,(Declarator *)$2,(DeclarationList *)$3,(CompoundStmt *)$4); }
	| declaration_specifiers declarator compound_statement						{ $$ = new FunctionDefinition((DeclarationSpecifiers *)$1, (Declarator *)$2, (CompoundStmt *)$3); }
	;
	
declaration_list :
	declaration								{ $$ = new DeclarationList((Declaration *)$1);}
	| declaration_list declaration			{ $$ = new DeclarationList((DeclarationList *)$1, (Declaration *)$2);}
	;



%%

#include <stdio.h>



extern char yytext[];
extern FILE * yyin;
extern int column;
extern int row;

int ex(ASTNode *p)
{
	TranslationUnit *trans = (TranslationUnit *) p;
	p->codeGen();
}

void yyerror(char *s)
{

  fflush(stdout);

  printf("\nrow:%d column:%d:%s \" %s \"\n", row, column,  s, yytext);

}
int main(int argc, char *argv[])
{
	yyin = fopen(argv[1],"r");
	yyparse();
	return 1;
}
